/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

import { Component, OhPrjSdkConfig, OhPrjSdkType, PathAndApiVersion, SdkInfoHandler, SimpleOhPrjSdkHandler, ApiVersion } from '@ohos/sdkmanager-common';
import { PathAndApiMap } from '@ohos/sdkmanager-common/build/src/core/util/path-and-api-map.js';
import fse from 'fs-extra';
import path from 'path';

import { CommonConst } from '../const/common-const.js';
import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import { OhosLogger } from '../utils/log/ohos-logger.js';

import { DefaultProgress } from './lib/default-progress.js';
import { Property } from './lib/property-get.js';
import { ohosPredict, proxyFun } from './sdk-util.js';
import ApiMeta = ProjectBuildProfile.ApiMeta;

const _log = OhosLogger.getLogger('SdkLoader');

export class OhosSdkLoader {
  private static container?: OhosSdkLoader;
  private sdkMap: PathAndApiMap = new PathAndApiMap();
  private sdkInfoHandler?: SdkInfoHandler;
  private property: Property;

  private constructor() {
    this.property = new Property(false);
  }

  static getInstance() {
    if (!OhosSdkLoader.container) {
      OhosSdkLoader.container = new OhosSdkLoader();
    }
    return OhosSdkLoader.container;
  }

  async getOhosSdkComponents(sdkVersion: ApiMeta, components: string[]) {
    // 结构化所需组件类型
    this.validateCache();
    const requiredComponents: PathAndApiVersion[] = [];
    const fullSdkVersion: ApiVersion = new ApiVersion(sdkVersion.fullVersion);
    components.forEach((cpn) => requiredComponents.push(new PathAndApiVersion(cpn, fullSdkVersion)));

    // 检查当前是否已存在所需组件
    const picked: Map<PathAndApiVersion, Component> = this.pickRequired(this.sdkMap, requiredComponents);
    const existenceResult = [...picked.values()].filter(
      (component) => !fse.existsSync(path.resolve(component.getLocation() ?? '', CommonConst.OHOS_SDK_COMPONENT_DEFINITION)),
    );
    if (components.length === picked.size && 0 === existenceResult.length) {
      return picked;
    }
    const predictComponents = ohosPredict(this.property.getSdkDir(), sdkVersion.api, components);
    if (0 === predictComponents.size) {
      this.sdkMap.clear();
    }
    for (const [key, component] of predictComponents.entries()) {
      if (!this.sdkMap.has(key)) {
        this.sdkMap.set(key, component);
      }
    }

    // 检查当前是否已存在所需组件
    const required: Map<PathAndApiVersion, Component> = this.pickRequired(this.sdkMap, requiredComponents);
    if (components.length === required.size) {
      return required;
    }
    if (!this.sdkInfoHandler) {
      this.initHandler();
    }

    // 下载所需组件并补充到已有组件库this.sdkMap中
    const downloaded = await this.sdkInfoHandler!.getOrDownload(requiredComponents);
    downloaded.forEach((component, key) => {
      if (!this.sdkMap.has(key)) {
        this.sdkMap.set(key, component);
      }
    });

    // 再次查找返回
    return this.pickRequired(this.sdkMap, requiredComponents);
  }

  private pickRequired(all: PathAndApiMap, required: PathAndApiVersion[]) {
    const result: Map<PathAndApiVersion, Component> = new Map();
    required.forEach((cpn) => {
      const component: Component | undefined = all.get(cpn);
      if (component) {
        result.set(cpn, component);
      }
    });
    return result;
  }

  initHandler(): void {
    const sdkConfig: OhPrjSdkConfig = OhPrjSdkConfig.builder(this.property.getSdkDir()).sdkProxy(proxyFun);
    const sdkHandler: SimpleOhPrjSdkHandler = new SimpleOhPrjSdkHandler(sdkConfig, new DefaultProgress());
    this.sdkInfoHandler = sdkHandler.getSdkHandler(OhPrjSdkType.OPENHARMONY);
  }

  private validateCache() {
    const currentProperty: Property = new Property(false);
    if (currentProperty.getSdkDir() === this.property.getSdkDir()) {
      return;
    }
    _log.debug('HarmonyOS sdk dir changed.');
    this.property = currentProperty;
    this.sdkMap.clear();
    this.initHandler();
  }
}
